﻿using SharpBgfx;
using SharpFont;
using System.IO;
using System.Numerics;

namespace GpuExample {
    static class EntryPoint {
        static void Main () {
            // create a platform window and kick off a separate render thread
            var window = new Window("Text Rendering Example", 1280, 720);
            window.Run(RenderThread);
        }

        unsafe static void RenderThread (Window window) {
            // initialize the renderer
            Bgfx.Init();
            Bgfx.Reset(window.Width, window.Height, ResetFlags.Vsync);
            Bgfx.SetDebugFeatures(DebugFeatures.DisplayText);
            Bgfx.SetViewClear(0, ClearTargets.Color | ClearTargets.Depth, unchecked((int)0xffffffff));

            var fontProgram = new Program(
                new Shader(MemoryBlock.FromArray(Shaders.FontVS)),
                new Shader(MemoryBlock.FromArray(Shaders.FontFS)),
                destroyShaders: true
            );

            var u_texColor = new Uniform("u_texColor", UniformType.Int1);
            var atlas = new TextureAtlas(4096);
            
            var font = FontCollection.SystemFonts.Load("Verdana");
            var analyzer = new TextAnalyzer(atlas);
            var buffer = new TextBuffer(12800);
            //buffer.Append(analyzer, font, "m");
            //buffer.Append(analyzer, font, "Hello, World! (¼)");


            buffer.Append(analyzer, font,
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus congue vitae augue sit amet laoreet. Etiam eros ligula, vestibulum non nisi a, convallis sodales odio. Integer dapibus ipsum eros, sit amet euismod ligula fringilla quis. Pellentesque placerat, dui vitae venenatis aliquam, augue eros porttitor erat, sit amet imperdiet dolor nulla nec justo. Etiam at elit vel diam consectetur venenatis vel et eros. In leo ante, vestibulum eu volutpat a, facilisis et justo. Sed semper arcu id lectus faucibus, ac pretium nunc sagittis. Praesent faucibus eu nisl non lacinia. Suspendisse suscipit vulputate velit, non sodales augue. In ante nulla, tempus vitae nisi tincidunt, dignissim venenatis elit. Phasellus fermentum turpis sed sapien dapibus, quis varius leo mattis. Nam nisl nibh, eleifend in maximus ac, ultricies ut eros.

Phasellus auctor magna erat, iaculis interdum purus porta vulputate. Etiam vel neque at justo dictum tincidunt. Etiam enim nibh, dapibus accumsan blandit suscipit, dignissim vitae quam. Duis at metus et nulla posuere malesuada ut at urna. Quisque eget arcu venenatis, gravida tellus volutpat, vehicula tellus. Pellentesque rutrum purus vel ante sodales sollicitudin. Phasellus ut elit blandit, maximus ipsum ut, varius nisi.

Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque volutpat in lectus sit amet pharetra. In mi justo, maximus sit amet viverra nec, posuere vel leo. Phasellus in justo quis ex semper suscipit. Pellentesque ut ornare purus.Donec et pretium metus. Integer dapibus est a nibh convallis pulvinar. Mauris metus diam, congue eget arcu volutpat, varius vehicula sapien. Donec posuere, massa et fringilla tincidunt, lacus ante fermentum sapien, ut dictum tellus erat id quam.Donec tempus urna velit, ac congue nibh egestas luctus. Praesent vel leo at enim imperdiet maximus non nec massa.

Pellentesque auctor ultricies accumsan. Vestibulum ipsum mi, tincidunt ut lacinia et, lobortis in lacus. Donec eu velit imperdiet, viverra mi ut, congue tortor. Vestibulum ac dui pretium, interdum tortor a, varius nulla. Nunc consequat neque sed sodales sagittis. Nullam condimentum metus sit amet sapien elementum, a pulvinar eros cursus. Sed eget elit tellus. Fusce ac pellentesque orci. Nullam sagittis malesuada elit, sed dignissim nibh sollicitudin malesuada. Mauris ac hendrerit enim. Aliquam ex urna, sagittis varius ex eu, commodo consequat tortor.

Praesent varius mauris sed lacus congue sollicitudin. Nulla lectus nunc, euismod id nibh quis, sollicitudin imperdiet neque. Maecenas suscipit quam sit amet venenatis cursus. Donec lacinia interdum rutrum. Phasellus quis odio justo. Duis sed justo quis quam rutrum consequat. Praesent et suscipit magna, eu condimentum mauris.Mauris in ligula odio. Integer tincidunt nisi et ipsum efficitur rutrum.");

            Bgfx.SetViewTransform(0, Matrix4x4.Identity, Matrix4x4.CreateOrthographicOffCenter(0, 1280, 720, 0, -1.0f, 1.0f));

            // main loop
            while (window.ProcessEvents(ResetFlags.Vsync)) {
                Bgfx.SetViewRect(0, 0, 0, window.Width, window.Height);

                Bgfx.SetTexture(0, u_texColor, atlas.Texture);
                Bgfx.SetProgram(fontProgram);
                buffer.Submit();

                Bgfx.Frame();
            }

            // cleanup
            Bgfx.Shutdown();
        }
    }

    struct PosColorTexture {
        public Vector2 Position;
        public Vector2 TexCoords;
        public int Color;

        public PosColorTexture (Vector2 position, Vector2 texcoords, int color) {
            Position = position;
            TexCoords = texcoords;
            Color = color;
        }

        public static readonly VertexLayout Layout = new VertexLayout()
            .Begin()
            .Add(VertexAttributeUsage.Position, 2, VertexAttributeType.Float)
            .Add(VertexAttributeUsage.TexCoord0, 2, VertexAttributeType.Float)
            .Add(VertexAttributeUsage.Color0, 4, VertexAttributeType.UInt8, normalized: true)
            .End();
    }

    static class Shaders {
        public static readonly byte[] FontVS = {
            0x56, 0x53, 0x48, 0x04, 0x01, 0x83, 0xf2, 0xe1, 0x01, 0x00, 0x0f, 0x75, 0x5f, 0x6d, 0x6f, 0x64, // VSH........u_mod
            0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, // elViewProj......
            0xd8, 0x02, 0x44, 0x58, 0x42, 0x43, 0x03, 0x3f, 0x85, 0xee, 0x20, 0x01, 0x00, 0xea, 0x08, 0x06, // ..DXBC.?.. .....
            0xb6, 0x7d, 0x8d, 0xf2, 0x28, 0xef, 0x01, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, 0x03, 0x00, // .}..(...........
            0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x49, 0x53, // ..,...........IS
            0x47, 0x4e, 0x68, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, // GNh...........P.
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
            0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ......V.........
            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x5f, 0x00, // .............._.
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, // ................
            0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x50, 0x4f, 0x53, 0x49, // ......COLOR.POSI
            0x54, 0x49, 0x4f, 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x4f, 0x53, // TION.TEXCOORD.OS
            0x47, 0x4e, 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, // GNl...........P.
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
            0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
            0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x62, 0x00, // ..............b.
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, // ................
            0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, // ......SV_POSITIO
            0x4e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, // N.COLOR.TEXCOORD
            0x00, 0xab, 0x53, 0x48, 0x44, 0x52, 0xc0, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x70, 0x00, // ..SHDR....@...p.
            0x00, 0x00, 0x59, 0x00, 0x00, 0x04, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, // ..Y...F. .......
            0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, // .._..........._.
            0x00, 0x03, 0x32, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, 0x32, 0x10, // ..2......._...2.
            0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, // ......g.... ....
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, // ......e.... ....
            0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x68, 0x00, // ..e...2 ......h.
            0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, // ......8.........
            0x00, 0x00, 0x06, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, // ..........F. ...
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0xf2, 0x00, 0x10, 0x00, 0x01, 0x00, // ......8.........
            0x00, 0x00, 0x56, 0x15, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, // ..V.......F. ...
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, // ................
            0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x01, 0x00, // ..F.......F.....
            0x00, 0x00, 0x38, 0x00, 0x00, 0x0b, 0xf2, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, // ..8...........F.
            0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, //  ..........@....
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
            0x00, 0x07, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, // ..........F.....
            0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x0b, 0xf2, 0x00, // ..F.......8.....
            0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x8e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // ......F. .......
            0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, // ...@.....?...?..
            0x80, 0x3f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x07, 0xf2, 0x00, 0x10, 0x00, 0x00, 0x00, // .?...?..........
            0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x01, 0x00, // ..F.......F.....
            0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x32, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x10, // ..6...2.......F.
            0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xf2, 0x00, 0x10, 0x00, 0x02, 0x00, // ......6.........
            0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xf2, 0x20, // ..F.......6.... 
            0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, // ......F.......6.
            0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x0e, 0x10, 0x00, 0x02, 0x00, // ... ......F.....
            0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0x32, 0x20, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x00, // ..6...2 ......F.
            0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x03, 0x05, 0x00, 0x01, 0x00, // ......>.........
            0x10, 0x00, 0x40, 0x00,                                                                         // ..@.
        };

        public static readonly byte[] FontFS = {
            0x46, 0x53, 0x48, 0x04, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0xac, 0x01, 0x44, 0x58, 0x42, 0x43, // FSH.........DXBC
            0xa4, 0x23, 0x5a, 0xc4, 0xcc, 0x18, 0x6f, 0x23, 0xe6, 0x28, 0xa6, 0x2c, 0x8d, 0x0d, 0xd5, 0x26, // .#Z...o#.(.,...&
            0x01, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, // ............,...
            0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x4e, 0x6c, 0x00, 0x00, 0x00, // ........ISGNl...
            0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........P.......
            0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, // ................
            0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // ................
            0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........b.......
            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, // ................
            0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, // SV_POSITION.COLO
            0x52, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0xab, 0x4f, 0x53, 0x47, 0x4e, // R.TEXCOORD..OSGN
            0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // ,........... ...
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
            0x0f, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xab, 0xab, // ....SV_TARGET...
            0x53, 0x48, 0x44, 0x52, 0xd0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, // SHDR....@...4...
            0x5a, 0x00, 0x00, 0x03, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x18, 0x00, 0x04, // Z....`......X...
            0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, // .p......UU..b...
            0xf2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0x32, 0x10, 0x10, 0x00, // ........b...2...
            0x02, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // ....e.... ......
            0x68, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x09, 0xf2, 0x00, 0x10, 0x00, // h.......E.......
            0x00, 0x00, 0x00, 0x00, 0x46, 0x10, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x46, 0x7e, 0x10, 0x00, // ....F.......F~..
            0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, // .....`......6...
            0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // ................
            0x36, 0x00, 0x00, 0x05, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, // 6...............
            0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x82, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, // ....8.... ......
            0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, // ........:.......
            0x36, 0x00, 0x00, 0x05, 0x72, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x12, 0x10, 0x00, // 6...r ......F...
            0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,                         // ....>.......
        };
    }
}
